package com.wly.login.user.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import com.wly.login.auth.token.TokenService;
import com.wly.login.common.ValidationException;
import com.wly.login.user.entity.User;
import com.wly.login.common.Result;
import com.wly.login.user.factory.LoginStrategyManager;
import com.wly.login.user.strategy.LoginStrategy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;


import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author wly
 */
@Validated
@RestController
@RequestMapping("/auth")
public class UserController {


	@Resource
	private TokenService tokenService;
	@Resource
	private RedisTemplate<String, String> redisTemplate;

	/**
	 * 登入
	 *
	 * @param user 用户信息
	 * @author wly
	 * @date 2025-02-16
	 */
	@PostMapping("/login/{type}")
	public Result<Map<String, String>> login(@PathVariable String type,@RequestBody User user) {
		try {
			// 1-选择登录方式
			LoginStrategy loginStrategy = LoginStrategyManager.getLoginStrategy(type);
			if (loginStrategy == null) {
				return Result.error("无效的登录方式");
			}
			// 2-登录
			loginStrategy.login(user);
			// 3-生成token
			String token = tokenService.generateToken(user.getId());
			// 4-返回结果
			Map<String, String> data = new HashMap<>();
			data.put("token", token);
			return Result.ok(data);
		} catch (ValidationException e) {
			throw e;
		} catch (Exception e) {
			throw new RuntimeException("登录失败", e);
		}
	}

	/**
	 * 用户登出接口
	 *
	 * @param token 用户 Token
	 * @return 登出结果
	 * @author wly
	 * @date 2025-02-16
	 */
	@PostMapping("/logout")
	public Result<String> logout(@RequestHeader("Authorization") String token) {

		// 1、校验
		if (StrUtil.isBlank(token)) {
			return Result.unauthorized();
		}

		// 2、查看过期时间
		// - 创建并解析JWT对象
		JWT jwt = JWT.of(token);
		// - token失效时间（毫秒）
		long expiration = jwt.getPayload().getClaimsJson().getLong("exp") * 1000;
		// - 当前时间
		long currentTime = System.currentTimeMillis();

		// 3、token未过期、加入黑名单
		if (expiration > currentTime) {

			// 剩余有效时间
			long residueTime = expiration - currentTime;
			redisTemplate.opsForValue().set(token, "invalid", residueTime, TimeUnit.MICROSECONDS);
		}
		return Result.ok("退出成功");
	}
}


// @RequestBody 序列化（请求体-->二进制）、反序列化（二进制-->User对象）
// @RestController 响应Controller，包装成响应报文（行、头、体）给前端
// 使服务器端 Token 失效：将 Token 加入黑名单或删除会话信息。
//黑名单逻辑：将失效的 Token 存入 Redis，并设置剩余有效时间，确保即使 Token 未过期也无法使用。
// 剩余有效时间：如果黑名单记录没有过期时间，那么就需要定期检查和清理过期的记录，这会增加系统的维护成本。通过使用剩余有效时间，这一步骤可以自动完成。
